/* Copyright 2018-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
 * applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, either express or implied. See the License for the specific
 * language governing permissions and limitations under the License.
 */
package com.github.drinkjava2.gosqlgo;

import static com.github.drinkjava2.gosqlgo.util.GsgStrUtils.getRandomClassName;
import static com.github.drinkjava2.gosqlgo.util.GsgStrUtils.isEmpty;
import static com.github.drinkjava2.gosqlgo.util.GsgStrUtils.positionOfPureChar;
import static com.github.drinkjava2.gosqlgo.util.GsgStrUtils.substringAfter;
import static com.github.drinkjava2.gosqlgo.util.GsgStrUtils.substringBefore;

import java.io.File;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.github.drinkjava2.gosqlgo.util.GsgFileUtils;
import com.github.drinkjava2.gosqlgo.util.GsgStrUtils;
import com.github.drinkjava2.gosqlgo.util.Systemout;

/**
 * Store static methods for DeployTool
 * 
 * @author Yong Zhu
 * @since 1.0.0
 */
@SuppressWarnings("all")
public class DeployToolUtils {

	/**
	 * Extract sql/java to server side for one html/javascript file, if forceDeploy
	 * is true, ignore if have FRONT control word, force extract to server side
	 */
	public static void oneFileToServ(File file,  boolean forceDeploy) {
		String text = GsgFileUtils.readFile(file.getAbsolutePath(), "UTF-8");
		boolean needTransfer = (text.contains("$qry(`") || text.contains("$java(`"));
		if (!needTransfer)
			return;

		Map<String, SqlJavaPiece> map = new LinkedHashMap<String, SqlJavaPiece>();
		String formated = formatText(file, text, map, "$qry(`", '`');
		for (Entry<String, SqlJavaPiece> item : map.entrySet()) {
			String key = item.getKey();
			SqlJavaPiece piece = item.getValue();
			if (piece.isFront() && !forceDeploy)
				formated = GsgStrUtils.replaceFirst(formated, key, "$qry(`" + piece.getOriginText() + "`");
			else if (!GsgStrUtils.containsWhitespace(piece.getOriginText()))
				formated = GsgStrUtils.replaceFirst(formated, key, "$qry(`" + piece.getOriginText() + "`");
			else {
				String className = "";
				if (isEmpty(piece.getId()))
					className = getRandomClassName(10);
				else
					className = GsgStrUtils.replace(piece.getId(), "#", "");
				String src =   QrySrcBuilder.instance.createSourceCode(className, piece);
				GsgFileUtils.writeFile(GoSqlGoEnv.instance.getDeployAbsolutePath() + "/" + className + ".java", src,
						"UTF-8");
				formated = GsgStrUtils.replaceFirst(formated, key, "$qry('" + className + "'");
			}
		}

		map.clear();
		formated = formatText(file, formated, map, "$java(`", '`');
		for (Entry<String, SqlJavaPiece> item : map.entrySet()) {
			String key = item.getKey();
			SqlJavaPiece piece = item.getValue();
			if (piece.isFront() && !forceDeploy)
				formated = GsgStrUtils.replaceFirst(formated, key, "$java(`" + piece.getOriginText() + "`");
			else {
				String className = "";
				if (isEmpty(piece.getId()))
					className = getRandomClassName(10);
				else
					className = GsgStrUtils.replace(piece.getId(), "#", "");
				String src =  JavaSrcBuilder.instance.createSourceCode(className, piece);
				GsgFileUtils.writeFile(GoSqlGoEnv.instance.getDeployAbsolutePath() + "/" + className + ".java", src,
						"UTF-8");
				formated = GsgStrUtils.replaceFirst(formated, key, "$java('" + className + "'");
			}
		}

		if (!text.equals(formated)) {
			GsgFileUtils.writeFile(file.getAbsolutePath(), formated, "UTF-8");
			Systemout.println("goServ => " + file.getAbsolutePath());
		}
	}

	private static String formatText(File file, String oldText, Map<String, SqlJavaPiece> map, String start,
			char endChar) {
		String result = oldText;
		boolean needTransfer = result.contains(start);
		while (needTransfer) {
			String front = substringBefore(result, start);
			String left = substringAfter(result, start);
			if (isEmpty(left))
				throw new IllegalArgumentException(
						"Error: " + start + " not closed ` in file: " + file.getAbsolutePath());

			int pos = positionOfPureChar(left, endChar);
			if (pos == -1)
				throw new IllegalArgumentException(
						"Error: " + start + " not found end ` in file: " + file.getAbsolutePath());

			String piece = left.substring(0, pos);
			String leftover = left.substring(pos + 1);
			SqlJavaPiece parsed = SqlJavaPiece.parseFromFrontText(piece);
			String key = "key" + GsgStrUtils.getRandomString(20);
			map.put(key, parsed);
			result = front + key + leftover;
			needTransfer = result.contains(start);
		}
		return result;
	}

	/**
	 * Push back sql/java from server side to HTML/JS, if forceGoFront is true,
	 * ignore if have SERV control word, force push back to front
	 */
	public static void oneFileToFront(File file, DeployTool deployTool, boolean forceGoFront) {
		String text = GsgFileUtils.readFile(file.getAbsolutePath(), "UTF-8");
		boolean needTransfer = (text.contains("$qry('") || text.contains("$java('"));
		if (!needTransfer)
			return;

		Map<String, SqlJavaPiece> map = new LinkedHashMap<String, SqlJavaPiece>();

		String formated = formatText(file, text, map, "$qry('", '\'');
		for (Entry<String, SqlJavaPiece> item : map.entrySet()) {
			String key = item.getKey();
			SqlJavaPiece piece = item.getValue();
			if (!GsgStrUtils.isLegalClassName(piece.getOriginText())) {
				formated = GsgStrUtils.replaceFirst(formated, key, "$qry('" + piece.getOriginText() + "'");
			} else {
				String javaSrcFileName = GoSqlGoEnv.instance.getDeployAbsolutePath() + "/" + piece.getOriginText()
						+ ".java";
				SqlJavaPiece newPiece = SqlJavaPiece.parseFromJavaSrcFile(
						GoSqlGoEnv.instance.getDeployAbsolutePath() + "/" + piece.getOriginText() + ".java");
				if (GsgStrUtils.isEmpty(newPiece.getOriginText()))
					formated = GsgStrUtils.replaceFirst(formated, key, "$qry('" + piece.getOriginText() + "'");
				else if (newPiece.isServ() && !forceGoFront)
					formated = GsgStrUtils.replaceFirst(formated, key, "$qry('" + piece.getOriginText() + "'");
				else {
					formated = GsgStrUtils.replaceFirst(formated, key,
							"$qry(`" + QrySrcBuilder.instance.createFrontText(newPiece) + "`");
					new File(javaSrcFileName).delete();
				}
			}
		}
		map.clear();

		formated = formatText(file, formated, map, "$java('", '\'');
		for (Entry<String, SqlJavaPiece> item : map.entrySet()) {
			String key = item.getKey();
			SqlJavaPiece piece = item.getValue();
			if (!GsgStrUtils.isLegalClassName(piece.getOriginText())) {
				formated = GsgStrUtils.replaceFirst(formated, key, "$java('" + piece.getOriginText() + "'");
			} else {
				String javaSrcFileName = GoSqlGoEnv.instance.getDeployAbsolutePath() + "/" + piece.getOriginText()
						+ ".java";
				SqlJavaPiece newPiece = SqlJavaPiece.parseFromJavaSrcFile(javaSrcFileName);
				if (GsgStrUtils.isEmpty(newPiece.getOriginText()))
					formated = GsgStrUtils.replaceFirst(formated, key, "$java('" + piece.getOriginText() + "'");
				else if (newPiece.isServ() && !forceGoFront)
					formated = GsgStrUtils.replaceFirst(formated, key, "$java('" + piece.getOriginText() + "'");
				else {
					formated = GsgStrUtils.replaceFirst(formated, key,
							"$java(`" + JavaSrcBuilder.instance.createFrontText(newPiece) + "`");
					new File(GoSqlGoEnv.instance.getDeployAbsolutePath() + "/" + piece.getOriginText() + ".java");
					new File(javaSrcFileName).delete();
				}
			}
		}
		map.clear();

		if (!text.equals(formated)) {
			GsgFileUtils.writeFile(file.getAbsolutePath(), formated, "UTF-8");
			Systemout.println("goFront => " + file.getAbsolutePath());
		}
	}

}
